# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: api\handlers\frontend\system_config.py
__author__ = "sanyi"
import logging, os.path, uuid, sqlalchemy.exc
from sqlalchemy import select as sql_select
from sqlalchemy import func as sql_func
from sqlalchemy import distinct as sql_distinct
from api.classes.frontend.auto import *
from api.handlers.frontend import FrontendResourceHandler
from db import Connection
from db.tables.system_config import SystemConfigRow, SystemConfigTable
from db.tables.system_config_mu import SystemConfigMuRow, SystemConfigMuTable
from server.http_responses.http_status_codes import Http204
from server.http_responses.http_errors import Http409, Http404
from settings_provider import settings
from db.data.users import (
    require_system_user,
    is_system_user,
    is_master_user,
    require_master_user,
    get_owner_id,
)
from helpers.updater import Updater
from helpers.setup_types import *
from db.tables.targets import TargetRow, TargetTypes
from db.tables.users import UserRow
from helpers.licensing.features import Features

logger = logging.getLogger("frontend_api_resources.SystemConfig")


class SystemConfig(FrontendResourceHandler):
    def enable_system_upgrade(self, **_):
        """
        :param _:
        :return:
        """
        if not is_setup_type(ON_PREMISE_MASTER):
            raise Http404()
        require_system_user(self.request_user)
        system_update_object = settings.get("system_update_object", None)
        if not system_update_object:
            raise Http409("No update mechanism enabled")
        if system_update_object.confirm_that_update_is_permitted():
            return Http204()
        raise Http409("Invalid updater status")

    def check_for_updates(self, **_):
        if not is_setup_type(ON_PREMISE_MASTER):
            raise Http404()
        require_system_user(self.request_user)
        updater = settings.get("system_update_object")
        if updater is None:
            return ClsUpdateInfo(
                new_update=False,
                update_status="none",
                build_number="-",
                minor_version="-",
                major_version="12",
            )
        else:
            if updater.update_status == "none":
                updates_data = False
                try:
                    updates_data = updater.check_for_updates()
                except Exception as e:
                    logger.error("check_for_updates failed with %s", e)

                if updates_data:
                    updater.update_info = updates_data
                    if updater.update_preference == "auto":
                        updater.update_status = "waiting_for_scans"
                    else:
                        updater.update_status = "waiting_for_user"
                    if updater.update_status == "none":
                        return ClsUpdateInfo(
                            new_update=False,
                            update_status="none",
                            build_number="-",
                            minor_version="-",
                            major_version="12",
                        )
            return ClsUpdateInfo(
                new_update=True,
                update_status=updater.update_status,
                build_number=str(updater.update_info["build_number"]),
                minor_version=str(updater.update_info["minor_version"]),
                major_version=str(updater.update_info["major_version"]),
            )

    def get_system_info(self, **_):
        response = dict(
            build_number="-",
            minor_version="-",
            major_version="-",
            update_info=ClsUpdateInfo(
                new_update=False,
                update_status="none",
                build_number="-",
                minor_version="-",
                major_version="-",
            ),
        )
        license_info = self.license.license_info
        license_info["features"] = list(self.license.features)
        license_info["limits"] = self.license.limits
        licensing_extra = dict()
        if is_setup_type_aws():
            response["confirmation_status"] = self.request_user["confirmation"]
            licensing_extra = dict(
                extra_std_target_count=0,
                extra_user_count=0,
                can_create_new_std_target=True,
                can_create_new_network_target=True,
                can_create_new_demo_target=True,
                can_create_new_user=True,
            )
            q_dt = (
                sql_select((sql_func.count(TargetRow.target_id),))
                .where(TargetRow.owner_id == get_owner_id(self.request_user))
                .where(TargetRow.type == TargetTypes.DEMO)
                .where(TargetRow.deleted_at.is_(None))
            )
            q_st = (
                sql_select((sql_func.count(sql_distinct(TargetRow.cah)),))
                .where(TargetRow.owner_id == get_owner_id(self.request_user))
                .where(TargetRow.type == TargetTypes.DEFAULT)
                .where(TargetRow.deleted_at.is_(None))
            )
            q_net = (
                sql_select((sql_func.count(sql_distinct(TargetRow.cah)),))
                .where(TargetRow.owner_id == get_owner_id(self.request_user))
                .where(TargetRow.type == TargetTypes.NETWORK_ONLY)
                .where(TargetRow.deleted_at.is_(None))
            )
            q_usr = (
                sql_select((sql_func.count(UserRow.user_id),))
                .where(UserRow.owner_id == get_owner_id(self.request_user))
                .where(UserRow.deleted_at.is_(None))
            )
            with Connection(self.current_shard_name) as (db):
                demo_target_count = db.execute(q_dt).scalar()
                std_target_count = db.execute(q_st).scalar()
                net_target_count = db.execute(q_net).scalar()
                child_user_count = db.execute(q_usr).scalar()
            licensing_extra["unique_std_target_count"] = std_target_count
            licensing_extra["unique_net_target_count"] = net_target_count
            licensing_extra["user_count"] = child_user_count + 1
            if self.license.max_targets is not None:
                if self.license.max_targets <= std_target_count:
                    licensing_extra["extra_std_target_count"] = (
                        std_target_count - self.license.max_targets
                    )
                    licensing_extra["can_create_new_std_target"] = False
            if self.license.max_network_targets is not None:
                if self.license.max_network_targets <= net_target_count:
                    licensing_extra["extra_network_target_count"] = (
                        net_target_count - self.license.max_network_targets
                    )
                    licensing_extra["can_create_new_network_target"] = False
            if self.license.max_demo_targets is not None:
                if self.license.max_demo_targets <= demo_target_count:
                    licensing_extra["can_create_new_demo_target"] = False
            if self.license.has_feature(Features.MULTI_USER):
                if self.license.max_users is not None:
                    if self.license.max_users <= child_user_count + 1:
                        licensing_extra["extra_user_count"] = (
                            child_user_count + 1 - self.license.max_users
                        )
                        licensing_extra["can_create_new_user"] = False
            if not self.license.has_feature(Features.MULTI_USER):
                licensing_extra["can_create_new_user"] = False
        if is_setup_type_on_premise():
            updater = settings.get("system_update_object", None)
            if updater is None or updater.update_status == "none":
                response["update_info"] = ClsUpdateInfo(
                    new_update=False,
                    update_status="none",
                    build_number="-",
                    minor_version="-",
                    major_version="12",
                )
            else:
                response["update_info"] = ClsUpdateInfo(
                    new_update=True,
                    update_status=updater.update_status,
                    build_number=str(updater.update_info["build_number"]),
                    minor_version=str(updater.update_info["minor_version"]),
                    major_version=str(updater.update_info["major_version"]),
                )
            version_info = settings.get("version_info", {})
            response["version_info"] = version_info
            response["build_number"] = str(version_info.get("build_number", 0))
            response["minor_version"] = str(version_info.get("minor_version", 0))
            response["major_version"] = str(version_info.get("major_version", 0))
            licensing_extra = dict(
                extra_std_target_count=0,
                extra_user_count=0,
                can_create_new_std_target=True,
                can_create_new_demo_target=True,
                can_create_new_user=True,
                target_deletion_allowance=settings["max_target_deletion_allowance"],
            )
            q_dt = (
                sql_select((sql_func.count(TargetRow.target_id),))
                .where(TargetRow.owner_id == get_owner_id(self.request_user))
                .where(TargetRow.type == TargetTypes.DEMO)
                .where(TargetRow.deleted_at.is_(None))
            )
            q_st = (
                sql_select((sql_func.count(sql_distinct(TargetRow.cah)),))
                .where(TargetRow.owner_id == get_owner_id(self.request_user))
                .where(TargetRow.type == TargetTypes.DEFAULT)
                .where(TargetRow.deleted_at.is_(None))
            )
            q_usr = (
                sql_select((sql_func.count(UserRow.user_id),))
                .where(UserRow.owner_id == get_owner_id(self.request_user))
                .where(UserRow.deleted_at.is_(None))
            )
            q_tdc = sql_select((SystemConfigRow.value,)).where(
                SystemConfigRow.name == "tdc"
            )
            with Connection(self.current_shard_name) as (db):
                demo_target_count = db.execute(q_dt).scalar()
                std_target_count = db.execute(q_st).scalar()
                child_user_count = db.execute(q_usr).scalar()
                tdc = db.execute(q_tdc).fetchone()
                if tdc:
                    tdc = tdc.value.get("deleted", 0)
                else:
                    tdc = 0
            licensing_extra["unique_std_target_count"] = std_target_count
            licensing_extra["user_count"] = child_user_count + 1
            if self.license.max_targets is not None:
                if self.license.max_targets <= std_target_count:
                    licensing_extra["extra_std_target_count"] = (
                        std_target_count - self.license.max_targets
                    )
                    licensing_extra["can_create_new_std_target"] = False
            if self.license.max_demo_targets is not None:
                if self.license.max_demo_targets <= demo_target_count:
                    licensing_extra["can_create_new_demo_target"] = False
            if self.license.has_feature(Features.MULTI_USER):
                if self.license.max_users is not None:
                    if self.license.max_users <= child_user_count + 1:
                        licensing_extra["extra_user_count"] = (
                            child_user_count + 1 - self.license.max_users
                        )
                        licensing_extra["can_create_new_user"] = False
            if not self.license.has_feature(Features.MULTI_USER):
                licensing_extra["can_create_new_user"] = False
            if self.license.has_feature(Features.DELETE_TARGETS):
                licensing_extra["target_deletion_allowance"] = 100000
            else:
                licensing_extra["target_deletion_allowance"] = max(
                    0, settings["max_target_deletion_allowance"] - tdc
                )
            response["licensing_extra"] = licensing_extra
            if self.is_request_by_master_account:
                license_info["license_key"] = self.license.license_data.get(
                    "license_key"
                )
            else:
                license_info["license_key"] = "-"
                license_info["email"] = "-"
            response["license"] = ClsLicenseInfo(**license_info)
            return ClsSystemInfo(**response)

    def get_configurations(self, **_):
        """
        :param _:
        :return:
        """
        result = dict()
        if is_setup_type(AWS):
            q = sql_select((SystemConfigMuRow,)).where(
                SystemConfigMuRow.user_id == get_owner_id(self.request_user)
            )
            su = is_master_user(self.request_user)
        else:
            if is_setup_type(ON_PREMISE_MASTER):
                su = is_system_user(self.request_user)
                q = sql_select((SystemConfigRow,))
            else:
                return ClsSystemConfig(**result)
            with Connection(self.current_shard_name) as (connection):
                for conf in connection.execute(q).fetchall():
                    if not su:
                        if conf.name not in ("excluded_hours_id",):
                            continue
                        result[conf.name] = conf.value

            return ClsSystemConfig(**result)

    def update_configurations(self, body, **_):
        """
        Require master user of the installation
        :param body:
        :param _:
        :return:
        """
        if is_setup_type(AWS):
            require_master_user(self.request_user)
        else:
            if is_setup_type(ON_PREMISE_MASTER):
                require_system_user(self.request_user)
            else:
                return Http204()
            configurations = ClsSystemConfig(
                ignored_required_keys=True, ignore_default_values=True, **body
            )
            email_notifications_changed = False
            with Connection(self.current_shard_name) as (connection):
                for name, value in configurations.__dict__.items():
                    if value == undefined:
                        continue
                    if is_setup_type(AWS):
                        if name not in ("excluded_hours_id", "notifications"):
                            continue
                        if name == "notifications":
                            email_notifications_changed = True
                            if not value:
                                if is_setup_type(ON_PREMISE_MASTER):
                                    q = SystemConfigTable.delete().where(
                                        SystemConfigRow.name == name
                                    )
                                    connection.execute(q)
                    else:
                        if is_setup_type(AWS):
                            q = (
                                SystemConfigMuTable.delete()
                                .where(SystemConfigMuRow.name == name)
                                .where(
                                    SystemConfigMuRow.user_id
                                    == get_owner_id(self.request_user)
                                )
                            )
                            connection.execute(q)
                            continue
                        if name == "proxy":
                            import xmltodict

                            proxy_settings = dict(
                                Activation=dict(
                                    ProxyHost="",
                                    ProxyPort="",
                                    ProxyUser="",
                                    ProxyPass="",
                                )
                            )
                            if value:
                                if value.get("enabled"):
                                    if value.get("protocol") == "http":
                                        if value.get("address"):
                                            proxy_settings = dict(
                                                Activation=dict(
                                                    ProxyHost=value.get("address"),
                                                    ProxyPort=value.get("port"),
                                                    ProxyUser=value.get("username"),
                                                    ProxyPass=value.get("password"),
                                                )
                                            )
                            file_path = os.path.join(
                                settings.get("base_storage"),
                                "general",
                                "Activation.xml",
                            )
                            data = xmltodict.unparse(proxy_settings)
                            open(file_path, "wt").write(data)
                        if name in ("excluded_hours_id",):
                            pass
                        if value is None:
                            if is_setup_type(ON_PREMISE_MASTER):
                                q = SystemConfigTable.delete().where(
                                    SystemConfigRow.name == name
                                )
                                connection.execute(q)
                            else:
                                if is_setup_type(AWS):
                                    q = (
                                        SystemConfigMuTable.delete()
                                        .where(SystemConfigMuRow.name == name)
                                        .where(
                                            SystemConfigMuRow.user_id
                                            == get_owner_id(self.request_user)
                                        )
                                    )
                                    connection.execute(q)
                                    continue
                                    value = str(uuid.UUID(value))
                                try:
                                    if is_setup_type(ON_PREMISE_MASTER):
                                        q = SystemConfigTable.insert().values(
                                            name=name, value=value
                                        )
                                        connection.execute(q)
                                    else:
                                        if is_setup_type(AWS):
                                            q = SystemConfigMuTable.insert().values(
                                                name=name,
                                                value=value,
                                                user_id=get_owner_id(self.request_user),
                                            )
                                            connection.execute(q)
                                except sqlalchemy.exc.IntegrityError:
                                    if is_setup_type(ON_PREMISE_MASTER):
                                        q = (
                                            SystemConfigTable.update(
                                                values=dict(value=value)
                                            )
                                        ).where(SystemConfigRow.name == name)
                                        connection.execute(q)
                                    else:
                                        if is_setup_type(AWS):
                                            q = (
                                                (
                                                    SystemConfigMuTable.update(
                                                        values=dict(value=value)
                                                    )
                                                )
                                                .where(SystemConfigMuRow.name == name)
                                                .where(
                                                    SystemConfigMuRow.user_id
                                                    == get_owner_id(self.request_user)
                                                )
                                            )
                                            connection.execute(q)

            if is_setup_type(ON_PREMISE_MASTER):
                if email_notifications_changed:
                    from helpers.mailer.settings_loader import (
                        on_premise_settings_loader,
                    )
                    from helpers.mailer.base_mailer import Mailer

                    mailer_object = settings.get("mailer_object")
                    if mailer_object:
                        mailer_object.sender.reload_settings(
                            on_premise_settings_loader(self.current_shard_name)
                        )
            return Http204()
